package com.ly.consumer.listeners;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.stereotype.Component;

import java.time.LocalTime;
import java.util.Map;

/**
 * - **Publisher**：生产者，不再发送消息到队列中，而是发给交换机
 * - **Exchange**：交换机，一方面，接收生产者发送的消息。另一方面，知道如何处理消息，例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作，取决于Exchange的类型。
 * - **Queue**：消息队列也与以前一样，接收消息、缓存消息。不过队列一定要与交换机绑定。
 * - **Consumer**：消费者，与以前一样，订阅队列，没有变化
 *
 * **Exchange（交换机）只负责转发消息，不具备存储消息的能力**，因此如果没有任何队列与Exchange绑定，或者没有符合路由规则的队列，那么消息会丢失！
 *
 * 交换机的类型有四种：
 *
 * - **Fanout**：广播，将消息交给所有绑定到交换机的队列。我们最早在控制台使用的正是Fanout交换机
 * - **Direct**：订阅，基于RoutingKey（路由key）发送给订阅了消息的队列
 * - **Topic**：通配符订阅，与Direct类似，只不过RoutingKey可以使用通配符
 * - **Headers**：头匹配，基于MQ的消息头匹配，用的较少。
 */
@Slf4j
@Component
public class MqListener {

//  @RabbitListener(queues = "simple.queue")
//  public void listenSimpleMessage(String msg) {
//      System.out.println("消费者收到了Simple.queue的消息:"+ msg);
//  }

  // *********************************************************************************
    @RabbitListener(queues = "work.queue")
    public void listenworkQueue1(String msg) throws InterruptedException {
        System.out.println("消费者1收到了work.queue的消息:"+ "【" + msg + "】" + LocalTime.now());
        Thread.sleep(20);
    }

    @RabbitListener(queues = "work.queue")
    public void listenworkQueue2(String msg) throws InterruptedException {
        System.err.println("消费者2收到............的消息:"+ "【" + msg + "】" + LocalTime.now());
        Thread.sleep(200);
    }

  // ***********************************************************************************
    // 广播 交换机
    @RabbitListener(queues = "fanout.queue1")
    public void listenfanoutQueue1(String msg) {
        System.out.println("消费者1收到了fanout.queue的消息:"+ msg);
    }

    @RabbitListener(queues = "fanout.queue2")
    public void listenfanoutQueue2(String msg) {
        System.out.println("消费者2收到了fanout.queue的消息:"+ msg);
    }

  // ***********************************************************************************
    // 订阅 交换机
    @RabbitListener(queues = "direct.queue1")
    public void listendirectQueue1(String msg) {
        System.out.println("direct.queue1的消息:【" + msg + "】");
    }

    @RabbitListener(queues = "direct.queue2")
    public void listendirectQueue2(String msg) {
        System.out.println("direct.queue2的消息:【" + msg + "】");
    }
  // ***********************************************************************************

    @RabbitListener(queues = "topic.queue1")
    public void listentopicQueue1(String msg) {
        System.out.println("topic.queue1的消息:【" + msg + "】");
    }

    @RabbitListener(queues = "topic.queue2")
    public void listentopicQueue2(String msg) {
        System.out.println("topic.queue2的消息:【" + msg + "】");
    }

  // ************************************************************************************

//
//    @RabbitListener(queues = "object.queue")
//    public void listentopicQueueJson(Map<String,Object> msg) {
//        System.out.println("topic.queue2的消息:"+ msg);
//    }
//
//
//
//    @RabbitListener(
//            bindings = @QueueBinding(
//                    value = @Queue(name = "direct.queue10",durable = "true"),
//                    exchange =@Exchange(name = "ly.direct",type = ExchangeTypes.DIRECT),
//                    key = {"red","blue","green"}
//            )
//    )
//    public void listendirectQueue10(String msg) {
//        System.out.println("direct.queue10的消息:"+ msg);
//    }

  // ***************************************************************************************
    // direct 直连 / 订阅 交换机 绑定 队列
    @RabbitListener(bindings = @QueueBinding(
                    value = @Queue(name = "direct.queue1"),
            exchange = @Exchange(name = "linyu.direct", type = ExchangeTypes.DIRECT),
            key = {"red","blue"}
            )
    )
    public void listenDirectQueue1(String msg){
        System.out.println("消费者1接收到direct.queue1的消息：【" + msg + "】");
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue2"),
            exchange = @Exchange(name = "linyu.direct", type = ExchangeTypes.DIRECT),
            key = {"red","yellow"}
    ))
    public void listenDirectQueue2(String msg){
        System.out.println("消费者2接收到direct.queue2的消息：【" + msg + "】");
    }

  // ***************************************************************************************
    // topic 通配符 交换机 绑定 队列
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name ="topic.queue1"),
            exchange = @Exchange(name = "linyu.topic", type = ExchangeTypes.TOPIC),
            key = "chain.#"
    ))
    public void listenTopicQueue1(String msg){
        System.out.println("消费者1接收到topic.queue1的消息:【" + msg + "】");
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue2"),
            exchange = @Exchange(name = "linyu.topic", type = ExchangeTypes.TOPIC),
            key = "#.news"
    ))
    public void listenTopicQueue2(String msg){
        System.out.println("消费者2接收到topic.queue2的消息:【" + msg + "】");
    }

   // ***************************************************************************************
   // 消费者接收 Object
    @RabbitListener(queues = "object.queue")
    public void listenSimpleQueueMessage(Map<String,Object> msg){
        System.out.println("消费者接收到object.queue消息：【" + msg + "】");
    }

   // ***************************************************************************************
    /**
     * 惰性队列：
     * 特征：1、接收到消息后直接存入磁盘而非内存
     *      2、消费者要消费消息时才会从磁盘中读取并加载到内存（也就是懒加载）
     *      3、支持数百万条的消息存储
     * 注意：在 3.12 版本后，LazyQueue 已经成为所有队列的默认格式。
     */
    // 声明式创建惰性队列
    @RabbitListener(queuesToDeclare = @Queue(
            name = "lazy.queue",
            durable = "true",
            arguments = @Argument(name = "x-queue-mode",value = "lazy")
    ))
    public void listenLazyQueue(String msg){
        log.info("接收到 lazy.queue 的消息:{}",msg);
    }

    @RabbitListener(queues = "simple.queue")
    public void listenSimpleQueueMessage(String msg){
        log.info("spring 消费者接收到消息:【" + msg + "】");
        if (true){
//            throw new MessageConversionException("故意的");
            throw new RuntimeException("故意的");
        }
        log.info("消息处理完成");
    }

   // *************************************************************************************
   // 声明延迟交换机
   @RabbitListener(bindings = @QueueBinding(
           value = @Queue(name = "delay.queue",durable = "true"),
           exchange = @Exchange(name = "delay.direct",delayed = "true"),
           key = "delay"
   ))
    public void listenDelayMessage(String msg) {
        log.info("接收到 delay.queue 的延迟消息：{}",msg);
   }

}
